﻿using System.Collections.Generic;

namespace Basic.RateLimit.Handler
{
    public class RateLimitFactory
    {
        public bool UseGroup { get; set; }

        /// <summary>
        /// 分组限流规则[Key:分组Id;Value:([Key:path前缀;Value:限流处理器])]
        /// </summary>
        public Dictionary<string, Dictionary<string, RateLimitHandler>> GroupLimitRules { get; private set; }

        /// <summary>
        /// 通用限流规则[Key:path前缀;Value:限流处理器]
        /// </summary>
        public Dictionary<string, RateLimitHandler> PublicLimitRules = new Dictionary<string, RateLimitHandler>();

        public RateLimitFactory()
        {
            GroupLimitRules = new Dictionary<string, Dictionary<string, RateLimitHandler>>();
        }

        /// <summary>
        /// 获取规则组
        /// </summary>
        /// <param name="group"></param>
        /// <returns></returns>
        private Dictionary<string, RateLimitHandler> GetRules(string group)
        {
            if (string.IsNullOrEmpty(group))
                return PublicLimitRules;
            return GroupLimitRules.TryGetValue(group, out var rules) && rules.Count > 0 ? rules : PublicLimitRules;
        }

        private RateLimitHandler GetHandler(string requestPath, Dictionary<string, RateLimitHandler> rules)
        {
            foreach (var kv in rules)
            {
                if (requestPath.StartsWith(kv.Key))
                {
                    return kv.Value;
                }
            }
            return null;
        }

        public bool CheckRateLimit(string requestPath, string group = null)
        {
            var dict = GetRules(group);
            if (dict != null && GetHandler(requestPath, dict) is RateLimitHandler handler)
            {
                return handler.CheckRateLimit();
            }
            return true;
        }

        public void AddRule(Dictionary<string, RateLimitHandler> newRule, string group = null)
        {
            if (string.IsNullOrEmpty(group))
            {
                AddRule(PublicLimitRules, newRule);
                return;
            }
            if (!GroupLimitRules.TryGetValue(group, out var oldRule))
            {
                GroupLimitRules[group] = newRule;
                return;
            }
            AddRule(oldRule, newRule);
        }

        private void AddRule(Dictionary<string, RateLimitHandler> oldRule, Dictionary<string, RateLimitHandler> newRule)
        {
            foreach (var kv in newRule)
            {
                if (oldRule.TryGetValue(kv.Key, out var handler))
                    handler.MaxLimit = kv.Value.MaxLimit;
                else
                    oldRule[kv.Key] = kv.Value;
            }

            foreach (var kv in oldRule)
            {
                if (!newRule.ContainsKey(kv.Key))
                    oldRule.Remove(kv.Key);
            }
        }
    }
}